package agents.profileragentbehaviuors;

import java.io.IOException;

import resource.Artifact;
import agents.ProfilerAgent;
import jade.core.AID;
import jade.core.behaviours.FSMBehaviour;
import jade.core.behaviours.OneShotBehaviour;
import jade.core.behaviours.SimpleBehaviour;
import jade.domain.FIPANames.InteractionProtocol;
import jade.lang.acl.ACLMessage;
import jade.lang.acl.UnreadableException;

public class AuctionParticipantBehaviour extends FSMBehaviour {
	private static final String LISTEN_FOR_START_OF_AUCTION = "A";
	private static final String LISTEN_FOR_CFP = "B";
	private static final String CALCULATE_ARTIFACT_WORTH = "C";
	private static final String DECIDE_UPON_CFP = "D";
	private static final String RESPOND_TO_CFP = "E";
	private static final String LISTEN_FOR_CONFIRMATION = "F";	
	private static final String DEREGISTER_AUCTION_PARTICIPANT_SERVICE = "G";
	
	private ProfilerAgent owner;
	private AID sender;
	private Artifact currentArtifact;
	private float currentPrice;
	private boolean answer;
	private float artifactWorth;
	
	public AuctionParticipantBehaviour(ProfilerAgent agent){
		super(agent);
		this.owner = agent;
		
		this.registerFirstState(new ListenForStartOfAuctionBehaviour(), LISTEN_FOR_START_OF_AUCTION);
		this.registerState(new ListenForCFPBehaviour(), LISTEN_FOR_CFP);
		this.registerState(new CalculateArtifactWorthBehaviour(), CALCULATE_ARTIFACT_WORTH);
		this.registerState(new DecideUponCFPBehaviour(), DECIDE_UPON_CFP);
		this.registerState(new RespondToCFPBehaviour(), RESPOND_TO_CFP);
		this.registerState(new ListenForConfirmationBehaviour(), LISTEN_FOR_CONFIRMATION);
		this.registerLastState(new DeregisterAuctionParticipantServiceBehaviour(), 
											DEREGISTER_AUCTION_PARTICIPANT_SERVICE);
		
		this.registerDefaultTransition(LISTEN_FOR_START_OF_AUCTION, LISTEN_FOR_CFP);
		this.registerDefaultTransition(DECIDE_UPON_CFP, RESPOND_TO_CFP);
		this.registerDefaultTransition(RESPOND_TO_CFP, LISTEN_FOR_CONFIRMATION);
		this.registerDefaultTransition(LISTEN_FOR_CONFIRMATION, LISTEN_FOR_CFP);
		
		this.registerDefaultTransition(LISTEN_FOR_CFP, CALCULATE_ARTIFACT_WORTH);
		this.registerDefaultTransition(CALCULATE_ARTIFACT_WORTH, DECIDE_UPON_CFP);
	}
	
	private class ListenForStartOfAuctionBehaviour extends SimpleBehaviour {
		boolean done = false;
		@Override
		public void action() {
			ACLMessage msg = myAgent.receive();
			if(msg != null){
				if(msg.getProtocol().equals(InteractionProtocol.FIPA_DUTCH_AUCTION) && 
					msg.getPerformative() == ACLMessage.INFORM){
					
					sender = msg.getSender();
					try {
						currentArtifact = (Artifact) msg.getContentObject();
						registerDefaultTransition(LISTEN_FOR_CFP, CALCULATE_ARTIFACT_WORTH);
						done = true;
					} catch (UnreadableException e) {
						e.printStackTrace();
						block();
					}
				} else {
					block();
				}
			}
			else{
				block();
			}
		}

		@Override
		public boolean done() {
			if (done){
				done = false;
				return true;
			} 
			return done;
		}
	}
	
	private class ListenForCFPBehaviour extends SimpleBehaviour {
		
		@Override
		public void action() {
			ACLMessage msg = myAgent.receive();
			if(msg != null){
				//New auction
				if(msg.getProtocol().equals(InteractionProtocol.FIPA_DUTCH_AUCTION) && 
								msg.getPerformative() == ACLMessage.CFP){
					
					try {
						//this is what should happen
						currentPrice = (Float) msg.getContentObject();
						done = true;
					} catch (UnreadableException e) {
						e.printStackTrace();
						
						replyNotUnderstood(msg.getSender());
						registerDefaultTransition(LISTEN_FOR_CFP, LISTEN_FOR_START_OF_AUCTION);
						done = true;
					}
				} 
				//auction canceled
				else if (msg.getProtocol().equals(InteractionProtocol.FIPA_DUTCH_AUCTION) && 
						msg.getPerformative() == ACLMessage.CANCEL){
					System.out.println(owner.getLocalName()+": Recieved CANCEL message. Listening for next auction.");
					registerDefaultTransition(LISTEN_FOR_CFP, LISTEN_FOR_START_OF_AUCTION);
					done = true;
				} 
				//sender was the auctioneer but he sent something undreadable
				else if (msg.getSender().equals(sender)){
					
					replyNotUnderstood(msg.getSender());	
					registerDefaultTransition(LISTEN_FOR_CFP, LISTEN_FOR_START_OF_AUCTION);
					done = true;
				}
				//sender was some random guy and i'll ignore him
				else {
					block();
				}
			}
			else{
				block();
			}
		}	
		
		boolean done = false;
		@Override
		public boolean done() {
			if (done){
				done = false;
				return true;
			} 
			
			return done;
		}
		
		
		//reply with a not understood message
		private void replyNotUnderstood(AID sender){
			ACLMessage replyMessage = new ACLMessage(ACLMessage.NOT_UNDERSTOOD);
			replyMessage.addReceiver(sender);
			replyMessage.setSender(owner.getAID());
			replyMessage.setProtocol(InteractionProtocol.FIPA_DUTCH_AUCTION);
			owner.send(replyMessage);
		}
	}
	
	//calculates the price i'm willing to give
	private class CalculateArtifactWorthBehaviour extends OneShotBehaviour {

		@Override
		public void action() {
			artifactWorth = currentPrice*(float)Math.random();
			
			System.out.println(owner.getLocalName()+ ": Hmm, a " + currentArtifact.getName() + "." +
					" This is worth " + artifactWorth + " for me.");
			
			registerDefaultTransition(LISTEN_FOR_CFP, DECIDE_UPON_CFP);
		}
		
	}
	
	//decides upon if i want the item or not
	private class DecideUponCFPBehaviour extends OneShotBehaviour {
		@Override
		public void action() {
			if (currentPrice <= artifactWorth){
				answer = true;
			} else {
				answer = false;
			}
		}
	}
	
	//responds my answer to the cfp
	private class RespondToCFPBehaviour extends OneShotBehaviour {

		@Override
		public void action() {
			try {
				ACLMessage replyMsg = new ACLMessage(ACLMessage.PROPOSE);
				replyMsg.setProtocol(InteractionProtocol.FIPA_DUTCH_AUCTION);
				replyMsg.setSender(owner.getAID());
				replyMsg.addReceiver(sender);
				replyMsg.setContentObject(new Boolean(answer));
				owner.send(replyMsg);
			} catch (IOException e) {
				e.printStackTrace();
			}
		}
		
	}
	
	//listens for confirmation on my answer
	private class ListenForConfirmationBehaviour extends SimpleBehaviour {

		@Override
		public void action() {
			ACLMessage msg = myAgent.receive();
			if(msg != null){
				if(msg.getProtocol().equals(InteractionProtocol.FIPA_DUTCH_AUCTION) && 
									msg.getPerformative() == ACLMessage.ACCEPT_PROPOSAL){
					if (!answer) {
						done = true;
					} else {
						System.out.println(owner.getLocalName()+ ": I won " + currentArtifact.getName() + "!!");
						done = true;
					}
				} else if (msg.getProtocol().equals(InteractionProtocol.FIPA_DUTCH_AUCTION) && 
											msg.getPerformative() == ACLMessage.REJECT_PROPOSAL){
					
					if (!answer) {
						System.out.println(owner.getLocalName()+ ": WHAT!? I'm NOT alowed to reject?!");
						done = true;
					} else {
						System.out.println(owner.getLocalName()+ ": I didn't win even though i bidded ::sadface::");
						done = true;
					}
				}
			}
			else{
				block();
			}
		}
		
		boolean done = false;
		@Override
		public boolean done() {
			if (done){
				done = false;
				return true;
			} 
			return done;
		}
	}
	
	private class DeregisterAuctionParticipantServiceBehaviour extends OneShotBehaviour {
		@Override
		public void action() {
			//NOT YET IMPLEMENTED
		}		
	}
}
